import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class FileUtils {
	
	/**
	 * return a list of files inside a folder
	 */
	public static List<String> generateFileList(String srcFolder){
		return generateFileList(srcFolder, null);
    }
	
	/**
	 * return a list of files inside a folder, with given suffix(ignore case) like ".csv", ".zip"
	 */
	public static List<String> generateFileList(String srcFolder, String suffix){
		File node = new File(srcFolder);
		List<String> result = new ArrayList<String>();
		 
    	//add file only
		if(node.isFile()){
			LogUtils.getInstance().error(null, "Source folder is a file! Please check");
		}
		
		if(node.isDirectory()){
			String[] subNote = node.list();
			for(String filename : subNote){
				if (suffix == null || filename.endsWith(suffix.toLowerCase()) || filename.endsWith(suffix.toUpperCase()))
					result.add(filename);
			}
		}
		return result;
    }
	
	/**
	 * return a list of files inside a folder, exclude files given suffix(ignore case) like ".csv", ".zip"
	 */
	public static List<String> generateFileListExludeSuffix(String srcFolder, String suffix){
		File node = new File(srcFolder);
		List<String> result = new ArrayList<String>();
		 
    	//add file only
		if(node.isFile()){
			LogUtils.getInstance().error(null, "Source folder is a file! Please check");
		}
		
		if(node.isDirectory()){
			String[] subNote = node.list();
			for(String filename : subNote){
				if (suffix == null || (!filename.endsWith(suffix.toLowerCase()) && !filename.endsWith(suffix.toUpperCase())))
					result.add(filename);
			}
		}
		return result;
    }


	public static void moveOutOfFolder(String folder_name, String file_name) {

		// Destination directory
		File dir = new File(folder_name);
		if (!dir.isDirectory()) {
			LogUtils.getInstance().error(null, "Directory not exists, move failed!");
			return;
		}

		// File (or directory) to be moved
		File file = new File(dir, file_name);
		if (!file.isFile()) {
			LogUtils.getInstance().error(null, "File not exists, move failed!");
			return;
		}

		// Move file out of the directory
		boolean success = file.renameTo(new File(dir.getParent(), file.getName()));

		if (success) {
			//System.out.println("Move " + file_name + " out of folder "+ folder_name + " succeed!");
			LogUtils.getInstance().info("Move " + file_name + " out of folder "
					+ folder_name + " succeed!");
		} else {
			LogUtils.getInstance().error(null,"Move " + file_name + " out of folder "
					+ folder_name + " failed!");
		}
	}

	/**
	 * move a file into a folder, issue error if found existing same name file
	 */
	public static void moveIntoFolder(String folder_name, String file_name) {

		// Destination directory
		File dir = new File(folder_name);
		if (!dir.isDirectory()) {
			LogUtils.getInstance().error(null,"Directory not exists, move failed!");
			return;
		}

		// File (or directory) to be moved
		File file = new File(file_name);
		if (!file.isFile()) {
			LogUtils.getInstance().error(null,"File not exists, move failed!");
			return;
		}

		// Move file to the directory

		boolean success = file.renameTo(new File(dir, file.getName()));
		if (success) {
			LogUtils.getInstance().info("Move " + file_name + " to folder "
					+ folder_name + " succeed!");
		} else {
			LogUtils.getInstance().error(null,"Move " + file_name + " to folder "
					+ folder_name + " failed!");
		}

	}
	
	/**
	 * move a file into a folder, overwrite the existing file with same name
	 */
	public static void moveIntoFolderReplaceExisting(String folder_name, String file_name) {

		// Destination directory
		File dir = new File(folder_name);
		if (!dir.isDirectory()) {
			LogUtils.getInstance().error(null,"Directory not exists, move failed!");
			return;
		}

		// File (or directory) to be moved
		File file = new File(file_name);
		if (!file.isFile()) {
			LogUtils.getInstance().error(null,"File not exists, move failed!");
			return;
		}

		// Move file to the directory
		try {
			Files.move(file.toPath(), dir.toPath().resolve(file.getName()), StandardCopyOption.REPLACE_EXISTING);
		} catch (IOException e) {
			LogUtils.getInstance().error(e, "unable to move " + file.getAbsolutePath() + " to " + dir.getAbsolutePath());
		}

	}
	
    /**
     * Unzip a zip file.
     * 
     * @param srcPath: the zip file source folder
     * @param filename: the zip file name
     * @param desPath: the desternation folder for all unzipped files    
     * @return a list of unzipped file path if successful, otherwise return null
     */
    public static List<String> unzip(String srcPath, String zipFilename, String desPath) {
    	String zipPath = srcPath + File.separator + zipFilename;
    	LogUtils.getInstance().info("Unzip file " +  zipPath);
        try {
            ZipFile zipFile = new ZipFile(zipPath);
            Enumeration enumeration = zipFile.entries();
            List<String> unzipFileList = new ArrayList<String>();

            // unzip the files individually
            while (enumeration.hasMoreElements()) {
                ZipEntry zipEntry = (ZipEntry) enumeration.nextElement();
                String filename = zipEntry.getName();
                String dataFilePath = "";
                try {

                    BufferedInputStream input = new BufferedInputStream(
                            zipFile.getInputStream(zipEntry));
                    int size;
                    byte[] buffer = new byte[1024];
                    dataFilePath = desPath + File.separator + filename;
                    BufferedOutputStream output = new BufferedOutputStream(
                            new FileOutputStream(dataFilePath), buffer.length);
                    while ((size = input.read(buffer, 0, buffer.length)) != -1) {
                        output.write(buffer, 0, size);
                    }
                    output.flush();
                    output.close();
                    input.close();
                    unzipFileList.add(dataFilePath);
                } catch (Exception ex) {
                   LogUtils.getInstance().error(ex, "Error unzipping energy data file " + filename);
                }
                
            }
            zipFile.close();
            return unzipFileList;
        } catch (Exception ex) {
        	LogUtils.getInstance().error(ex, "Error processing zip file " + zipPath);
            return null;
        }
    }
    
    /**
     * Unzip a zip file.
     * 
     * @param srcPath: the zip file source folder
     * @param filename: the zip file name
     * @param desPath: the desternation folder for all unzipped files    
     * @param ziphistoryPath: the temp folder for all processed zip files 
     * @return a list of unzipped file path if successful, otherwise return null
     */
    public static List<String> unzipAndMove(String srcPath, String zipFilename, String desPath, String ziphistoryPath) {
    	String zipPath = srcPath + File.separator + zipFilename;
    	LogUtils.getInstance().info("Unzip file " +  zipPath);
        try {
            ZipFile zipFile = new ZipFile(zipPath);
            Enumeration enumeration = zipFile.entries();
            List<String> unzipFileList = new ArrayList<String>();

            // unzip the files individually
            while (enumeration.hasMoreElements()) {
                ZipEntry zipEntry = (ZipEntry) enumeration.nextElement();
                String filename = zipEntry.getName();
                String dataFilePath = "";
                try {
                    BufferedInputStream input = new BufferedInputStream(
                            zipFile.getInputStream(zipEntry));
                    int size;
                    byte[] buffer = new byte[1024];
                    dataFilePath = desPath + File.separator + filename;
                    BufferedOutputStream output = new BufferedOutputStream(
                            new FileOutputStream(dataFilePath), buffer.length);
                    while ((size = input.read(buffer, 0, buffer.length)) != -1) {
                        output.write(buffer, 0, size);
                    }
                    output.flush();
                    output.close();
                    input.close();
                    unzipFileList.add(dataFilePath);
                } catch (Exception ex) {
                   LogUtils.getInstance().error(ex, "Error unzipping energy data file " + filename);
                }
                
            }
            zipFile.close();
            moveIntoFolderReplaceExisting(ziphistoryPath, zipPath);
            return unzipFileList;
        } catch (Exception ex) {
        	LogUtils.getInstance().error(ex, "Error processing zip file " + zipPath);
            return null;
        }
    }
    
    static final String OUTPUT_SUFFIX = ".zip";
    
    /**
     * Zip sourceFile from srcPath to desPath
     */
    public static void zip(String srcPath, String sourceFile, String desPath){
 
     byte[] buffer = new byte[1024];
 
     try{
    	String fileNameWithourSuffix = getFileNameWithoutSuffix(sourceFile);
    	String zipFile = desPath + File.separator + fileNameWithourSuffix + OUTPUT_SUFFIX;
    	FileOutputStream fos = new FileOutputStream(zipFile);
    	ZipOutputStream zos = new ZipOutputStream(fos);
 
    	LogUtils.getInstance().info("Output to Zip : " + zipFile);
    	ZipEntry ze= new ZipEntry(sourceFile);
    	zos.putNextEntry(ze);

    	FileInputStream in = new FileInputStream(srcPath + File.separator + sourceFile);

    	int len;
    	while ((len = in.read(buffer)) > 0) {
    		zos.write(buffer, 0, len);
    	}

    	in.close();
    	zos.closeEntry();
    	//remember close it
    	zos.close();
    }catch(IOException ex){ 
       LogUtils.getInstance().error(ex, "Error zipping energy data file " + sourceFile);
    }
   }
 
	/**
	 * return file name without the suffix ".csv"
	 */
    public static String getFileNameWithoutSuffix(String sourceFile) {
    	String temp = sourceFile;
    	if (temp.endsWith(".CSV")) {
    		temp.replace(".CSV", ".csv");
    	}
    	if (temp.endsWith(".csv")) {
    		return temp.substring(0, temp.indexOf(".csv")); 
    	} else {
    		return temp;
    	}
	}

	public static void main(String[] args) {

	//	move_outof_folder("original", "test.csv");
	//	move_into_folder("postproc", "test.csv");
	//	unzip(".", "NEM12#13062400001000000#GLOBALM#BLDALIV.ZIP", "postproc");
//		System.out.println(File.separator);
//		String sourceFile = "12345.csv";
//		System.out.println( sourceFile.substring(0, sourceFile.indexOf(".csv")));
		zip("postproc", "test.csv", "original");
		generateFileList("postproc", ".zip");

	}

}